package com.information.manage.basic.common.utils;

import com.information.manage.basic.common.constant.ConfigureData;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.Base64;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * User: Initial Heart
 * Date: 2022-03-06.
 * Description:  文件操作
 * Version: V1.0
 */
@Component
@Slf4j
public class FileUtils {

    @Resource
    private ConfigureData configureData;

    /**
     * @param img 图片文件
     * @param suffix 保存后的后缀名
     * @return 文件路径
     */
    public String savePic(MultipartFile img, String suffix) {
        if (img == null) {
            return "";
        }
        InputStream inputStream = null;
        try {
            inputStream = img.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return savePic(inputStream, suffix);
    }

    /**
     * @param inputStream 输入流
     * @param suffix 文件后缀名
     * @return 文件路径
     */
    public String savePic(InputStream inputStream, String suffix) {
        String filePath = configureData.pictureLocalPath;
        String picName = UUID.randomUUID() + "." + suffix;
        File file = createFile(filePath, picName, true);
        try (FileOutputStream stream = new FileOutputStream(file)) {
            int count = 0;
            byte[] buffer = new byte[2048];
            while ((count = inputStream.read(buffer)) != -1) {
                stream.write(buffer, 0, count);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return configureData.pictureRelativePath + picName;
    }

    /**
     * @param base64
     * @return 存放base64的路径
     */
    public String saveBase64(String base64){
        String filePath = configureData.fingerprintLocalPath;
        String fileName = UUID.randomUUID().toString();
        File file = createFile(filePath, fileName, true);
        byte[] bytes = Base64.getDecoder().decode(base64);
        try (InputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
             FileOutputStream fileOutputStream = new FileOutputStream(file)) {
            int count = 0;
            byte[] buff = new byte[2048];
            while ((count = byteArrayInputStream.read(buff)) != -1){
                fileOutputStream.write(buff, 0, count);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return configureData.fingerprintRelativePath + fileName;
    }

    /**
     * 创建文件
     * @param filePath 文件路径
     * @param fileName 文件名称  如果文件名称不存在则会随机生成
     * @param isCover 如果存在 是否覆盖
     * @return
     */
    public File createFile(String filePath, @NonNull String fileName, @NonNull Boolean isCover){
        if (!filePath.endsWith("/") && !fileName.startsWith("/")) filePath = filePath.concat("/");
        File file = new File(filePath + fileName);
        try {
            if (isCover){
                if (file.exists() && file.isFile()) {
                    file.delete();
                }
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 根据路径删除指定的目录或文件，无论存在与否
     *@param sPath 要删除的目录或文件
     *@return 删除成功返回 true，否则返回 false。
     */
    public boolean deleteFolder(String sPath) {
        boolean  flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {  // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }

    /**
     * 删除单个文件
     * @param   sPath    被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(configureData.pictureLocalPath.substring(0, configureData.pictureLocalParent.lastIndexOf("/")) + sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     * @param   sPath 被删除目录的文件路径
     * @return  目录删除成功返回true，否则返回false
     */
    public boolean deleteDirectory(String sPath) {
        //如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) break;
            } //删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前目录
        return dirFile.delete();
    }


    /**
     * 删除目录（文件夹）以及目录下的文件
     * @param   sPath 被删除目录的文件路径
     * @return  目录删除成功返回true，否则返回false
     */
    public boolean deleteDir(String sPath) {
        //如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteOneFile(files[i].getAbsolutePath());
                if (!flag) break;
            } //删除子目录
            else {
                flag = deleteDir(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前目录
        return dirFile.delete();
    }

    private boolean deleteOneFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 重命名文件(即移动文件)
     * @param oldPath 原路径
     * @param newPath 新路径
     * @return
     */
    public boolean renameFile(String oldPath, String newPath){
        File file = new File(oldPath);
        if (file.exists() && file.isFile()){  // 原文件存在才能执行操作
            if (newPath.endsWith("/")){
                newPath = newPath.substring(0, newPath.length()-1);
            }
            // 递归创建不存在的目录
            recursionMkdir(newPath.substring(0, newPath.lastIndexOf("/")));
            if (file.renameTo(new File(newPath))){
                log.info("文件重命名成功, {} -> {}", oldPath, newPath);
                return true;
            }else {
                // 当新路径的文件名存在时可能导致重命名失败
                log.info("文件重命名失败, {}", oldPath);
                return false;
            }
        }else {
            log.info("文件原路径不存在, path = {}", oldPath);
            return false;
        }
    }

    /**
     * 文件复制
     * @param sourcePath 原文件地址
     * @param destPath 新文件地址
     */
    public boolean copyFile(String sourcePath, String destPath) {
        boolean flag = false;
        File sourceFile = new File(sourcePath);
        if (sourceFile.exists() || sourceFile.isFile()){
            if (destPath.endsWith("/")){
                destPath = destPath.substring(0, destPath.length()-1);
            }
            // 递归创建不存在的目录
            recursionMkdir(destPath.substring(0, destPath.lastIndexOf("/")));
            try(InputStream is = new FileInputStream(sourceFile);
                OutputStream os = new FileOutputStream(new File(destPath))) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = is.read(buffer)) > 0) {
                    os.write(buffer, 0, length);
                }
                flag = true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    /**
     * 递归创建目录
     * @param dir 目录路径
     */
    private static void recursionMkdir(String dir){
        String prePath = dir.substring(0, dir.indexOf("/")+1);
        String suffixPath = dir.substring(dir.indexOf("/"));
        // 去除首位的'/'
        if (suffixPath.startsWith("/")) suffixPath = suffixPath.substring(1);
        // 末尾添加'/' 用于后面的判断文件路径是否结束
        if (!suffixPath.endsWith("/")) suffixPath = suffixPath.concat("/");
        while (suffixPath.lastIndexOf("/") != -1){  //存在子路径
            String prePathSub = suffixPath.substring(0, suffixPath.indexOf("/"));
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(prePath).append(prePathSub);
            File file = new File(stringBuilder.toString());
            if (!file.exists() || !file.isDirectory()){  // 不存在该目录时才创建
                file.mkdir();
            }
            prePath = stringBuilder.append("/").toString();
            suffixPath = suffixPath.substring(suffixPath.indexOf("/")+1);
        }
    }

}
